package com.spzx.channel.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.spzx.channel.domain.vo.ItemVo;
import com.spzx.channel.service.ItemService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.core.utils.JwtUtils;
import com.spzx.common.core.utils.StringUtils;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.product.api.domain.Product;
import com.spzx.product.api.domain.ProductDetails;
import com.spzx.product.api.domain.ProductSku;
import com.spzx.product.api.domain.vo.SkuPriceVo;
import com.spzx.product.api.domain.vo.SkuStockVo;
import com.spzx.product.api.service.RemoteProductService;
import com.spzx.user.api.domain.UserBrowseHistory;
import com.spzx.user.api.service.RemoteUserBrowseHistoryService;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

@Service
public class ItemServiceImpl implements ItemService {

    @Autowired
    private RemoteProductService remoteProductService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;
    @Autowired
    private RemoteUserBrowseHistoryService remoteUserBrowseHistoryService;


    @Override
    public ItemVo getItemBySkuId(Long skuId) {
        //获取布隆过滤器
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter("sku:bloom:filter");
        //判断当前skuid是否存在布隆过滤器中
        if (!bloomFilter.contains(skuId)){
            throw  new ServiceException("该商品不存在");
        }

        /**
         * R<ProductSku>：表示 R 类的一个实例，它持有 ProductSku 类型的数据。R 类通常包含几个关键属性，
         * 如状态码（用于表示调用是否成功）、消息（用于提供调用结果的描述或错误信息）和数据（即实际返回的业务数据
         *
         * getData()：这是 R 类中的一个方法，用于返回封装在 R 实例中的数据
         *
         *
         * */
        //创造一个Item空对象
        ItemVo itemVo = new ItemVo();

        /**
         * 异步编排涉及到的类和方法：
         *      类：CompletableFuture可以使原本串行执行的代码，变为并行执行，提高代码执行速度。
         *      方法：
         *          runAsync：异步任务没有返回值
         *          supplyAsync：异步任务带返回值
         *          thenAcceptAsync：接收上一个任务的结果之后执行异步任务，没有返回值
         *          allOf：汇总所有任务
         *          join：阻塞等待所有任务都执行完才执行下面的操作
         *
         * @param skuId
         * @return
         */

        //1.异步获取商品Sku信息,带返回值
        CompletableFuture<ProductSku> futureProductSku = CompletableFuture.supplyAsync(() -> {
            //远程调用商品微服务获取商品Sku信息
            R<ProductSku> productSkuById = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);
            //通过状态码,判断是否失败
            if (R.FAIL==productSkuById.getCode()){
                //抛出异常
                throw new ServiceException(productSkuById.getMsg());
            }
            //获取商品Sku的信息
            ProductSku productSku = productSkuById.getData();
            //设置商品SKu信息
            itemVo.setProductSku(productSku);
            return productSku;
        }, threadPoolExecutor);

        //1.1接受到商品Sku信息后,异步获取商品信息,不带返回值
        CompletableFuture<Void> futureProduct = futureProductSku.thenAcceptAsync(productSku -> {

            //根据商品id获取商品信息
            R<Product> productById = remoteProductService.getProduct(productSku.getProductId(), SecurityConstants.INNER);
            //通过状态码,判断是否失败
            if (R.FAIL==productById.getCode()){
                //抛出异常
                throw new ServiceException(productById.getMsg());
            }

            //获取商品信息
            Product product = productById.getData();
            itemVo.setProduct(product);

            //获取商品轮播图
            String sliderUrls = product.getSliderUrls();
            //将字符串转换为数组
            String[] split = sliderUrls.split(",");
            //将数组转换为集合
            List<String> sliderUrlsList = Arrays.asList(split);
            //设置商品轮播图列表
            itemVo.setSliderUrlList(sliderUrlsList);

            //获取商品规格信息
            String specValue = product.getSpecValue();
            //将字符串转换为json格式的数组
            JSONArray jsonArray = JSON.parseArray(specValue);
            itemVo.setSpecValueList(jsonArray);

        }, threadPoolExecutor);
        //1.2接受到商品Sku信息后,异步获取商品详情图片信息   ,不带返回值
        CompletableFuture<Void> futureDetails = futureProductSku.thenAcceptAsync(productSku -> {
            //远程调用微服务获取商品详情图片列表
            R<ProductDetails> productDetailsById = remoteProductService.getProductDetails(productSku.getProductId(), SecurityConstants.INNER);
            //通过状态码,判断是否失败
            if (R.FAIL==productDetailsById.getCode()){
                //抛出异常
                throw new ServiceException(productDetailsById.getMsg());
            }
            //获取商品详细图标列表
            ProductDetails productDetails = productDetailsById.getData();
            String[] split1 = productDetails.getImageUrls().split(",");
            List<String> productDetailsList = Arrays.asList(split1);
            itemVo.setDetailsImageUrlList(productDetailsList);

        }, threadPoolExecutor);
        //1.3接受到商品Sku信息后,异步获取商品规格与商品Sku信息,不带返回值
        CompletableFuture<Void> futureSpecValueSkuId= futureProductSku.thenAcceptAsync(productSku -> {


            //调用商品微服务获取商品规格对应商品SkuId的信息
            R<Map<String, Long>> skuSpecValueById = remoteProductService.getSkuSpecValue(productSku.getProductId(), SecurityConstants.INNER);
            if (R.FAIL==skuSpecValueById.getCode()){
                //抛出异常
                throw new ServiceException(skuSpecValueById.getMsg());
            }
            //获取
            Map<String, Long> skuSpecValueMap = skuSpecValueById.getData();
            itemVo.setSkuSpecValueMap(skuSpecValueMap);

        }, threadPoolExecutor);
        //2.异步获取商品价格信息,无返回值
        CompletableFuture<Void> futureSkuPriceVo = CompletableFuture.runAsync(() -> {
            //调用远程微服务根据skuId获取最新价格信息
            R<SkuPriceVo> skuPriceById = remoteProductService.getSkuPrice(skuId, SecurityConstants.INNER);
            //通过状态码,判断是否失败
            if (R.FAIL==skuPriceById.getCode()){
                //抛出异常
                throw new ServiceException(skuPriceById.getMsg());
            }
            //获取最新价格信息
            SkuPriceVo skuPriceVo = skuPriceById.getData();
            //设置
            itemVo.setSkuPrice(skuPriceVo);

        }, threadPoolExecutor);
        //3.异步获取商品库存信息,无返回值
        CompletableFuture<Void> futureSkuStockVo = CompletableFuture.runAsync(() -> {

            //获取商品库存信息
            R<SkuStockVo> skuStockById = remoteProductService.getSkuStock(skuId, SecurityConstants.INNER);
            //通过状态码,判断是否失败
            if (R.FAIL==skuStockById.getCode()){
                //抛出异常
                throw new ServiceException(skuStockById.getMsg());
            }
            //获取商品库存信息
            SkuStockVo skuStockVo = skuStockById.getData();
            itemVo.setSkuStockVo(skuStockVo);

        }, threadPoolExecutor);

        //汇总6个任务
        CompletableFuture.allOf(
                futureProductSku,
                futureProduct,
                futureSkuStockVo,
                futureDetails,
                futureSkuPriceVo,
                futureSpecValueSkuId)
                .join();

        //获取用户id
        String token = SecurityUtils.getToken();
        String userId = JwtUtils.getUserId(token);
        if (StringUtils.hasText(userId)){
            //远程调用用户微服务保存浏览记录
            //创建UserBrowseHistory对象
            UserBrowseHistory userBrowseHistory = new UserBrowseHistory();
            //设置用户id
            userBrowseHistory.setUserId(Long.parseLong(userId));
            //设置商品skuid
            userBrowseHistory.setSkuId(skuId);
            //远程调用用户微服务保存浏览记录
            remoteUserBrowseHistoryService.saveUserBrowseHistory(userBrowseHistory,SecurityConstants.INNER);

        }

        return itemVo;
    }
}
